<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/5/14 0014
 * Time: 下午 3:35
 */

namespace App\Enum;

use App\Utility\BaseEnum;
use App\Common\BaseComm;
use App\Common\AuthCommon;

/**
 * 棋牌的配置参数分类
 * 保存当前棋牌的说明数据
 * @author XCH
 *
 */
class CardEnum
{
    /**
     * 状态值，游戏步骤 结算完成
     * @var int
     */
    const GAME_STEP_0 = 0;  //默认匹配
    const GAME_STEP_1 = 1;  //抢庄
    const GAME_STEP_2 = 2;  //下注
    const GAME_STEP_3 = 3;  //发牌
    const GAME_STEP_4 = 4;  //拼牌完成
    const GAME_STEP_5 = 5;  //结算完成
    
    
    /*
     *百人牛牛新添加
     */
    const BR_GAME_STEP_0 = 0;  //准备
    const BR_GAME_STEP_1 = 1;  //洗牌
    const BR_GAME_STEP_2 = 2;  //发牌
    const BR_GAME_STEP_3 = 3;  //下注
    const BR_GAME_STEP_4 = 4;  //停止下注
    const BR_GAME_STEP_5 = 5;  //派奖
    const BR_GAME_STEP_6 = 6;   //休息
    
    //状态列表
    const GAME_BRNN_STEP = [
        0 => '准备',
        1 => '洗牌',
        2 => '发牌',
        3 => '下注',
        4 => '停止下注',
        5 => '派奖',
        6 => '休息'
    ];
    
    //牌花色：大小王
    const CARD_COLORS = [0=>'方块',1=>'梅花',2=>'红桃',3=>'黑桃',4 => '王'];
    const CARD_COLORS_ICO = [0=>'♦',1=>'♣',2=>'♥',3=>'♠'];
    const CARD_FULL_LIST =  [
        0x01,0x11,0x21,0x31,  //方块A~黑桃A
        0x02,0x12,0x22,0x32,  //方块2~黑桃2
        0x03,0x13,0x23,0x33,  //方块3~黑桃3
        0x04,0x14,0x24,0x34,  //方块4~黑桃4
        0x05,0x15,0x25,0x35,  //方块5~黑桃5
        0x06,0x16,0x26,0x36,  //方块6~黑桃6
        0x07,0x17,0x27,0x37,  //方块7~黑桃7
        0x08,0x18,0x28,0x38,  //方块8~黑桃8
        0x09,0x19,0x29,0x39,  //方块9~黑桃9
        0x0A,0x1A,0x2A,0x3A,  //方块10~黑桃10
        0x0B,0x1B,0x2B,0x3B,  //方块J~黑桃J
        0x0C,0x1C,0x2C,0x3C,  //方块Q~黑桃Q
        0x0D,0x1D,0x2D,0x3D,  //方块K~黑桃K
    ];
    const CARD_SMALL_W = 0x42;          //小王
    const CARD_BIGG_W = 0x43;           //大王
    
    //牌的号码值1－13
    const CARD_NUMS = ['1'=>1,'2'=>2,'3'=>3,'4' => 4,'5' => 5,'6'=>6,'7'=>7,'8'=>8,'9'=>9,'A'=>10,'B'=>11,'C'=>12,'D'=>13];
    const CARD_NUMS_TEND = ['A','B','C','D'];
    
    //牌对应的名称：1到K 
    const CARD_NUM_NAME = ['1'=>'A','2'=>'2','3'=>'3','4' => '4','5' => '5','6'=>'6','7'=>'7','8'=>'8','9'=>'9','10'=>'10','11'=>'J','12'=>'Q','13'=>'K'];
    
    
    //扑克牌的操作类型
    const DZPK_TYPE_0 = 0;  //弃牌
    const DZPK_TYPE_1 = 1;  //过牌
    const DZPK_TYPE_2 = 2;  //跟注
    const DZPK_TYPE_3 = 3;  //加注
    const DZPK_TYPE_4 = 4;  //ALL IN
    
    
    /**
     * 牛牛的等级大小；
     * @var 16进制值
     */
    const GAME_0X2E = 14;   // 等级状态值 ：47 五小牛
    const GAME_0X2D = 13;   // 等级状态值 ：46 四炸
    const GAME_0X2C = 12;   // 等级状态值 ：45 五花牛
    const GAME_0X2B = 11;   // 等级状态值 ：44 四花牛
    const GAME_0X2A = 10;   // 等级状态值 ：43 牛牛
    const GAME_0X29 = 9;    // 等级状态值 ：42 牛九
    const GAME_0X28 = 8;	// 牛八
    const GAME_0X27 = 7;	// 牛七
    const GAME_0X26 = 6;	// 牛六
    const GAME_0X25 = 5;	// 牛五
    const GAME_0X24 = 4;	// 牛四
    const GAME_0X23 = 3;	// 牛三
    const GAME_0X22 = 2;	// 牛二
    const GAME_0X21 = 1;	// 牛一
    const GAME_0X20 = 0;	// 无牛
    
    //游戏类型的名称 五小牛，四炸，五花牛，四花牛，牛牛，牛九.... > 牛一，没牛
    const GAME_NIUNIU_LEVEL = [
        14=>'五小牛',
        13=>'四炸',
        12=>'五花牛',
        11=>'四花牛',
        10=>'牛牛',
        9=>'牛九',
        8=>'牛八',
        7=>'牛七',
        6=>'牛六',
        5=>'牛五',
        4=>'牛四',
        3=>'牛三',
        2=>'牛二',
        1=>'牛一',
        0=>'无牛',
    ];
    
    
    
    
    
    /**
     * 构造函数
     * @param array $options 参数
     * @access public
     */
    public function __construct($options = [])
    {
    }
    
    //计算点数；
    public static function getCardDott($cval=false) {
        if($cval===false)return FALSE;
        $res = $cval & 0x0f ;
        return $res;
    }
    //计算花色；
    public static function getCardHua($cval=false) {
        if($cval===false)return FALSE;
        $res =  ($cval & 0xf0) / 16 ;
        return $res;
    }
    
    /**
     * 获取完整的一副牌
     * @param  bool $wangflag 是否有大王和小王
     */
    public static function getFullCards($wangflag = true){
        $cardFullArray = []; //默认的牌是54张牌；
        $all_C = self::CARD_NUM_NAME;
        $all_R = self::CARD_COLORS;
        $all_Rico = self::CARD_COLORS_ICO;
        $allCrds = self::CARD_FULL_LIST;
        //所有牌数据；
        foreach ($allCrds as $card){
            //printf("0x%x",$card);                     //打印十六进制
            $dot =  self::getCardDott($card);
            $hua =  self::getCardHua($card);
            if($hua === false || $hua === 4)  continue ;         //计算花色和点数；
            $cardTxt = isset($all_C[$dot]) ? $all_C[$dot]: '';
            $colorIco = isset($all_Rico[$hua]) ? $all_Rico[$hua] : '';
            $huaName = isset($all_R[$hua]) ?$all_R[$hua] : "";
            $colorval = (isset($colorIco) && in_array($colorIco, ['♣','♠'])) ? 'black': 'red'; //KEY值；
            $cardFullArray[] = ["t"=>"0x". dechex($card),'name'=>$colorIco.$cardTxt,"ico"=> $colorIco,"text"=> $huaName.$cardTxt ,"key"=> $card ,"color" => $colorval];
        }
        //组装的KEY加添加大小王；
        if($wangflag === true){
            $cardFullArray[] = ['name'=>"▲JOKER","ico"=> "▲","text"=> "小王" ,"key"=> self::CARD_SMALL_W ,"color" => 'black',"t"=>"0x". dechex(self::CARD_SMALL_W)];   //小王
            $cardFullArray[] = ['name'=>"★JOKER","ico"=> "★","text"=> "大王" ,"key"=> self::CARD_BIGG_W ,"color" => 'red',"t"=>"0x". dechex(self::CARD_BIGG_W)];     //大王
        }
        return $cardFullArray ;
    }
    
    
    //根据ID值获取牌信息
    public static function getCardInfo($colorid,$cardnum = 0){
        //空牌；
        if(!$colorid) return false ;
        if($colorid == '0' && $cardnum == '0'){
            return ['name'=> '无牌',"ico"=> '',"key"=> ''];
        }
        
        $colorN = isset(self::CARD_COLORS[$colorid]) ? self::CARD_COLORS[$colorid] : '';
        $colorIco = isset(self::CARD_COLORS_ICO[$colorid]) ? self::CARD_COLORS_ICO[$colorid] : '';
        $cName = isset(self::CARD_NUM_NAME[$cardnum]) ? self::CARD_NUM_NAME[$cardnum] : '';
        $cVal = isset(self::CARD_NUMS[$cardnum]) ? self::CARD_NUMS[$cardnum] : '';
        $fullName = $colorN.$cName;
        //判斷是不是大小王；
        if (in_array($colorid, [4,5])) {
            $fullName = $colorN ; 
            $cVal = 0; //没有大小值
        }
        return array('name'=>$colorN.$cName,"ico"=> $colorIco,"key"=> $cVal);
    }
    
    /**
     * 获取字段串组成的牌大小； 
     * @param string $char
     * @return array| array|string[][]|number[][]
     */
    public static function getCardName($char) {
        $cardInfo = [];
        if(!$char || strlen($char) < 2) return $cardInfo ;
        $chatlist = str_split($char,2); //两个一组分隔为数组；
        if(!empty($chatlist)){
            //数组中取第一位做为值；
            foreach ($chatlist as $key => $onechar) {
                $colorid = substr("{$onechar}", 0,1);
                $cardnum = substr("{$onechar}", 1,1); //数字
                $cardInfo[$key] = self::getCardInfo($colorid,$cardnum);
            }
        }
        return !empty($cardInfo) ? $cardInfo : [];
    }
    
    
    /**
     * 生成牌规则
     * 游戏一、 抢庄牛牛
        ?  如：值为 360c2c1418 0000000000 360c2c1418 0000000000 1
        ? 字段规则第一位是花色，第二位数是牌值，第三位是花色，第四位数是牌值，以此类推
        ? 每个玩家 5 张手牌共占 10 位，依次为 1-4 号座位的玩家
        ? 最后面一位表示庄家的座位号,1-4 分别对应 1-4 号位
        ? 字符与花色对应关系、字符与牌值对应关系同德州扑克
        ? 例： 值为：360c2c14180000000000360c2c141800000000001 表示：1 号位玩家手牌♠6♦Q♥ Q♣4♣8；2 号位没有玩家；3 号位玩家手牌♠6♦Q♥Q♣4♣8；4 号位没有玩家；庄家是 1号位的玩家
     */
    public static function createRoomGameQZNN($playerNum,$param = FALSE,$sigle = false) {
        $everyCard = 5; //每人5张牌
        if(!$playerNum || !$everyCard || intval($everyCard) > 10 ) return false ;
        $fullCards = self::getFullCards(false); //牌的数据；
        //echo json_encode($fullCards);exit ;
        $fullCards = !empty($fullCards) ? array_column($fullCards, null,'key') : false ;
        $allCards = !empty($fullCards) ? array_column($fullCards,'key') : false ; //所有牌值； 
        @shuffle($allCards);    //洗牌；
        @shuffle($allCards);    //洗牌；
        @shuffle($allCards);    //洗牌；
        $useCards = $lastUserCards =  [];
        $useCardsName = [];
        $valIndex = 0 ;                      //每个玩家取5张牌；
        foreach ($allCards as $r => $paval){ //牌值；
            $thisYl = $valIndex % $playerNum;
            $pinfo = isset($fullCards[$paval])? $fullCards[$paval] :false ;
            if (isset($pinfo) && !empty($pinfo)) {
                //把玩家对应位置的牌值加上去；
                $oneUscard = isset($useCards[$thisYl]) ? $useCards[$thisYl] : [];
                if(empty($oneUscard) || (!empty($oneUscard) && sizeof($oneUscard) < $everyCard)){
                    $useCards[$thisYl][] = $paval;  //把玩家位置的值带上；
                    $useCardsName[$thisYl][] = isset($pinfo["name"]) ? $pinfo["name"] : "";     //牌值；
                }
                $valIndex ++;
            }
        }
        if(!$useCards) return false ;   //牌的数据；
        foreach ($useCards as $pr => $pkey) {
            $pailist = [];
            $paiarr = isset($useCardsName[$pr]) ? $useCardsName[$pr]: false ;
            if(isset($pkey) && !empty($pkey) && !empty($paiarr)){
                foreach ($pkey as $r => $val){  //配置数据
                    $huaval = self::getCardHua($val);   //花色
                    $dottval = $dott_text = self::getCardDott($val);  //计算单个值的点数
                    if(isset($val) && $huaval != 4 && $dottval > 10 ){  $dottval = 10 ;  }
                    $pailist[] = ['key'=>$val,"name"=> isset($paiarr[$r]) ? $paiarr[$r]: "", "dott" => $dottval,"t_dot" =>$dott_text ];
                }
                //$valIndex = $pr + 1;            //取位置内容；
                $lastUserCards[$pr] = !empty($pailist) ? array_column($pailist,'key') : FALSE;
            }
        }
        return $lastUserCards;
    }
    
    /**
     * 生成德洲扑克的牌数据
     * @param int $playerNum
     * @param boolean $param
     * @param boolean $sigle
     */
    public static function createRoomGameDZPK($playerNum,$param = FALSE,$sigle = false){
        $allCards = self::CARD_FULL_LIST;     //所有手牌信息； 都要保存(40张牌 1－9 白板)；
        if (!$allCards) {
            return FALSE;
        }
        @shuffle($allCards);    //洗牌；
        $everyCard = 2;         //每人2张牌
        
        //记录索引值；
        $userCards = [];
        //每个用户发2张牌；
        for ($pr = 0; $pr < $playerNum ; $pr++) {
            $offset = $pr * $everyCard;
            $userCards[$pr] = array_slice($allCards, $offset, $everyCard);
        }
        
        //取五张公共牌数据；
        $offset2 = $playerNum * $everyCard;
        
        $userCards["common"] = array_slice($allCards, $offset2, 5); //五张公共牌的数据
        //发牌先不解析；
        return  $userCards ; //手牌数据； 
    }
    
    
    
    
    //获取牛的点数
    protected static function getNiuDottod($notnums,&$jqk_num = 0,& $keyvalues = false) {
        $resList = [];
        $allNumVals = self::CARD_NUMS;
        $wangArr = array(self::CARD_BIGG_W,self::CARD_SMALL_W);
        foreach ($notnums as $n => $numstr){
            if(in_array($numstr, $wangArr))continue ;   //没有王；
            $dottNum = self::getCardDott($numstr);      //计算牌点，1－13值 echo "0x". dechex($numstr)."<br>";
            $keyvalues[$numstr] = $dottNum;             //计算牌值位，1－13值
            
            //计算单个值的点数
            $dottval = intval($dottNum);                
            if(isset($numstr) && $dottNum > 10 ){ 
                $jqk_num ++;                            //大于10为花牌
                $dottval = 10 ;
            }
            $resList[$numstr] =  $dottval;              //点数 
        }
        return $resList;
    }
    
    
    /**
     * 计算牛牛的大小值
     * @param boolean $nums 牛牛的牌值KEY
     * @param number $niuLevel 牌值的等级，
     * @param number $niu_mutle 牌值的倍数，
     * @return boolean|number[]|string[]|mixed[]
     */
    public static function dealNiuNiuLevel($nums = false , & $niuLevel = 0,& $niu_mutle = 1) {
        if(!$nums) return false ;
        $baseLevels = self::GAME_NIUNIU_LEVEL;
        //牛等级  牛牛牌大小： 五小牛，四炸，五花牛，四花牛，牛牛，牛九.... > 牛一，没牛
        $jqk_num = 0;           //五花的数目
        $maxCardDott = 0;       //取出最大牌的点（K > Q > J > 10 ）和花色；
        $ifThreeNiu = false ;
        $keyvalues = false ;    //KEY值大小
        $allNums = self::getNiuDottod($nums,$jqk_num,$keyvalues); //计算牛牛的规则；
        
        //最大的点数；
        $max_ddt = max($allNums);
        $all_ddt = array_sum($allNums); //总和；
        $all_ddt_val = $all_ddt % 10;   //总和取余数为0；
        
        //取牌值计算法：最大牌值；12 = C
        $max_pval = max($keyvalues);
        $uniqueDotts = array_unique($allNums);      //去重点数；
        $paiValsArr = array_count_values($keyvalues);
        $uniqueArr = array_unique($keyvalues);      //去重
        $paiValsArr_new = !empty($paiValsArr) ? array_values($paiValsArr): FALSE;
        /* print_r($allNums); 
        print_r($keyvalues); 
        print_r($uniqueArr);
        print_r($uniqueDotts);
        var_dump($max_pval . ' '. $jqk_num);
        print_r($allNums); 
        print_r($paiValsArr);exit ;
         */ 
        
        $maxCardChar = '';  //公共的取最大牌点值；
        $newarr = [];       //最大牌为当前牌值；
        $niuGroups = "";    //牛组号码分布
        if (isset($paiValsArr[$max_pval]) && intval($paiValsArr[$max_pval]) === 1) { //只有一张牌为最大的
            $maxCardChar  = array_search($max_pval,$keyvalues);
        }else if(isset($paiValsArr[$max_pval]) && intval($paiValsArr[$max_pval]) > 1){
            foreach ($keyvalues as $pint => $value) { if(isset($value) && intval($value) == $max_pval) $newarr[] = $pint; }//取出多个；
            if(!empty($newarr)) {               //排下序取第一个
                @krsort($newarr);
                $maxCardChar  = reset($newarr); //取大的KEY值 ；
            }
        }
        
        //1、五小牛; 5张牌的点数都小于5，且和小于等于10
        if($max_ddt < 5 && $all_ddt> 0 && intval($all_ddt) <= 10){  //满足条件；
            $niu_mutle = 4 ;                    //四倍牌值
            $niuLevel = self::GAME_0X2E; 
        }
        
        //2、四炸; 5张牌的有四张相同；若5张牌既符合四炸又符合五花牛则按照大的计算牌型。
        else if (isset($paiValsArr_new) && sizeof($paiValsArr_new) === 2 && !empty($paiValsArr) && ($paiValsArr_new[0] == 1 || $paiValsArr_new[1] == 1)) {
            $niu_mutle = 4 ;                    //四倍牌值
            $niuLevel = self::GAME_0X2D;    //取出四炸的值；为max_valu = 12 = C = 红桃Q
            $maxCardChar = array_search(4, $paiValsArr);  //取出四炸的值和牌的花色；(点数)
            //通过点数取四个花色的牌值；
            if($keyvalues && !empty($keyvalues) && isset($maxCardChar) && intval($maxCardChar) > 0 ){
                $onewarr = [];
                foreach ($keyvalues as $onek => $mxdd ){
                    if($maxCardChar == $mxdd){$onewarr[] = $onek; }
                }
                $niuGroups = !empty($onewarr) ? implode(',', $onewarr) : "";
            }
        }
        
        //3、五花牛；5张牌为花的任意牌；
        else if (isset($jqk_num) && intval($jqk_num) === 5) {
            $niu_mutle = 4 ;                    //四倍牌值
            $niuLevel = self::GAME_0X2C;
        }
        
        //3、四花牛；5张牌为花的任意牌；(花色数目：$jqk_num ＝ 4，所有点数为10点)
        else if (isset($jqk_num) && intval($jqk_num) === 4 && !empty($uniqueDotts) && sizeof($uniqueDotts) === 1) {
            $niu_mutle = 4 ;                    //四倍牌值
            $niuLevel = self::GAME_0X2B;
        }
        
        //计算牛几的公共算法；
        else {
            //只有中间有三位和值为10的存在就表明可以组成牛；
            foreach($allNums as $k => $val){
                foreach($allNums as $k2 => $v){
                    if($k2 == $k) continue ;
                    foreach($allNums as $k3 => $vl){
                        if($k3 == $k || $k3 == $k2) continue ;
                        $sum = $val + $v + $vl;
                        if($sum % 10 == 0){
                            $ifThreeNiu = true;
                            //记录牛的号码值；分组；
                            $niuGroups = implode(',', [$k,$k2,$k3]);
                            break;
                        }
                    }
                }
            }
            //计算牛牛的规则就是最后取余数据；
            if($ifThreeNiu == true){
                //3、牛牛；5张牌为总和为10点 ； 如 2 3 5 J 10 , 2 8 k k k ,
                if (isset($all_ddt) && intval($all_ddt) > 10 && $all_ddt_val === 0) {
                    $niu_mutle = 3 ;                                        //三倍牌值
                    $niuLevel = self::GAME_0X2A;
                }else{
                    $niuLevel = self::GAME_0X2A - (10 - $all_ddt_val);  //取数据；
                    if($all_ddt_val >= 7 ){ 
                        $niu_mutle = 2;                                     // 七八九牛 为 2倍牌值
                    }  
                }
            }else{
                //无牛计算
                $niuLevel = self::GAME_0X20;
            }
        }
        $niuName = isset($baseLevels[$niuLevel]) ?$baseLevels[$niuLevel] : "";
        $niuLevs = array("key"=> $niuLevel ,'name'=> $niuName,"maxCardKey" => $maxCardChar,"mutl_value"=> $niu_mutle,"niuGroups"=>$niuGroups);
        return $niuLevs;
    }
    
    
    
    /**
     * 取最大牌值； 
     * @param array $cards
     * @param number $maxdott
     */
    public static function getMaxCardValue($cards, & $maxdott = 0){
        $maxPai = FALSE ;   //取最大值出来； 
        $cInfo = [];        //取最大牌的数据
        foreach ($cards as $carval){
            $val = self::getCardDott($carval);
            $huaval = self::getCardHua($carval);
            $cInfo[$carval] = ["num"=> $carval,"dot"=> $val,"hua"=> $huaval];
        }
        
        foreach ($cInfo as $carinfo){
            //取最大的值；
            if (!empty($maxPai) && isset($maxPai["dot"]) && isset($carinfo["dot"])) {
                if(isset($carinfo['dot']) && intval($carinfo['dot']) > intval($maxPai["dot"]) ) { 
                    $maxPai = $carinfo; //点数直接大取的
                }else if(intval($carinfo['dot']) === intval($maxPai["dot"]) && intval($carinfo["hua"]) > intval($maxPai["hua"])) {  //黑桃(3)最大 ，  
                    $maxPai = $carinfo; //点数相同，比较花色
                }
            }else{
                $maxPai = $carinfo; //首次
            }
        }
        //取点数；
        if(isset($maxPai) && isset($maxPai['dot'])){
            $maxdott = intval($maxPai['dot']);
        }
        return $maxPai;
    }
    
    
    /**
     * 比较大小相同等级时；闲赢还是庄赢；
     * @param array $zjRes 庄
     * @param boolean $xjInfo 闲
     * @return boolean
     */
    public static function gatherWhoWin($zjNiuLevel,$zjRes,$xjInfo = false){
        $lastWin = 1 ;
        BaseEnum::Logger("结算ZJ： RES － {$zjNiuLevel} ".json_encode($zjRes),'user-login');
        BaseEnum::Logger("结算XJ： RES ---- ".json_encode($xjInfo),'user-login');
        
        $zjdott = 0;
        $xjdott = 0;
        //取出手牌中点数和花色都是最大牌的值；
        $maxZj = self::getMaxCardValue($zjRes["cards"], $zjdott);       //庄 最大牌
        $maxXj = self::getMaxCardValue($xjInfo["cards"], $xjdott);      //闲 最大牌
        //比相同牛时的数据：
        if(isset($zjNiuLevel) && $zjNiuLevel === self::GAME_0X2D){              //比炸弹；谁大；
            //四炸：比谁的炸值大 ；
            if (isset($zjRes["maxCardKey"]) && isset($xjInfo["maxCardKey"]) && self::getCardDott($zjRes["maxCardKey"]) < self::getCardDott($xjInfo["maxCardKey"]) ) {
                $lastWin = 2;
            }
        }else{  //其它比较最大牌
            if ($zjdott > 0 && $xjdott > 0 && $zjdott < $xjdott ) { //闲家点数大； 
                $lastWin = 2;
            }else if($zjdott > 0 && $xjdott > 0 && $zjdott === $xjdott &&  intval($maxZj['hua']) < intval($maxXj['hua'])){ //闲家点数相同，花色大；
                $lastWin = 2;
            }
        }
        return $lastWin;
    }
    
    
    /**
     * TODO 结算逻辑统一处理
     * A: 房间底注
     * M：庄家牌型对应的倍数
     * N：闲家牌型对应的倍数
     * X：庄家抢庄倍数
     * Y：闲家下注倍数
          * 庄家胜利所赢 ＝ A*M*X*Y －抽水
          * 庄家失败所输 ＝ A*N*X*Y
          * 闲家胜利所赢 ＝ A*N*X*Y －抽水
          * 闲家失败所输 ＝ A*M*X*Y
          * 最高 12 * 1 * 抢庄3倍 * 下注倍数(?)  = 2100
     * @param boolean $params
     */
    public static function dealRoomGameQZNN($zjdata = false , $xjdata = false , $fjdata = false,&$returndata = false) {
        BaseEnum::Logger("结算QZNN： ING ---- ".json_encode($zjdata),'user-login');
        $zjNiuLevel = 0; //比牌操作；庄家跟每个闲家一一对比；
        $zjcode = isset($zjdata['cards']) ? $zjdata['cards'] : false;                   //庄家的牌数据；
        $zjMutle = isset($zjdata['mainMutle']) ? intval($zjdata['mainMutle']) : 1;      //庄家倍数；
        $zjSeatNo = isset($zjdata['seatNo']) ? intval($zjdata['seatNo']) : 0;           //庄家座位号；
        $zjUserId = isset($zjdata['userId']) ? intval($zjdata['userId']) : 0;           //庄家UID；
        $zjOldFee = isset($zjdata['userPoints']) ? floatval($zjdata['userPoints']) : AuthCommon::getLoginUserPoints($zjUserId); //庄家余额；
        $zjCellScore = 0;   //庄家有效下注
        $zjTotalMoney = 0;  //庄家的总钱
        $allCards = [$zjSeatNo => $zjcode];
        $moneyArr = [$zjSeatNo=>array()];
        $gameUtype = isset($fjdata["gpKey"]) ? $fjdata["gpKey"] : "";                       //游戏类型
        $fjmoney = isset($fjdata["everyPoints"]) ? floatval($fjdata["everyPoints"]) : 0;    //房间低注金额
        $fjmaxPeop = isset($fjdata["maxPlayer"]) ? intval($fjdata["maxPlayer"]) : 0;    //房间低注金额
        $zjRes = self::dealNiuNiuLevel($zjcode,$zjNiuLevel);
        if(!empty($zjdata) && !empty($xjdata) && sizeof($xjdata) >0 && !empty($zjRes) && $fjmoney > 0 && $zjSeatNo >= 0){
            $zjFees = [];
            $xjSWin = []; //闲家结算分数(不抽水)
            $zjCardmutl = isset($zjRes['mutl_value']) ? $zjRes['mutl_value'] : 1;     //牌型倍数
            if (isset($zjRes['niuGroups']) && !empty($zjRes['niuGroups'])) {
                $zjcode = BaseEnum::changeGroupArray($zjcode,$zjRes['niuGroups']) ;
            }
            $zjRes['cards'] = $zjcode;
            //echo '庄-><br>'.print_r($zjRes,true);
            foreach ($xjdata as $xjinfo){
                $xjLevel = -1;      //闲家牛等级
                $xjMoney = 0;       //闲家赢的钱
                $cellScore = $xjWater = 0;     //闲家有效下注额
                
                $xjBets = isset($xjinfo['mainMutle']) ? intval($xjinfo['mainMutle']) : 1;      //闲家下注倍数；
                $xianjCard =  isset($xjinfo['cards']) ? $xjinfo['cards'] : false; 
                $xjSeatNo = isset($xjinfo['seatNo']) ? intval($xjinfo['seatNo']) : 0;           //庄家座位号；
                $xjUserId = isset($xjinfo['userId']) ? intval($xjinfo['userId']) : 0;           //庄家座位号；
                $xjOldFee = isset($xjinfo['userPoints']) ? floatval($xjinfo['userPoints']) : AuthCommon::getLoginUserPoints($xjUserId); //闲家余额；
                $allCards[$xjSeatNo] = $xianjCard;
                
                $xjRes = CardEnum::dealNiuNiuLevel($xianjCard,$xjLevel);
                $lastWin = 1 ;  //通过计算谁家赢：1-庄赢，2-闲赢,
                if(!empty($xianjCard) && !empty($xjRes) && $xjLevel >= 0 && $xjSeatNo >= 0){
                    $xjCardMut = isset($xjRes['mutl_value']) ? $xjRes['mutl_value'] : 1;     //牌型倍数
                    if (isset($xjRes['niuGroups']) && !empty($xjRes['niuGroups'])) {
                        $xianjCard = BaseEnum::changeGroupArray($xianjCard,$xjRes['niuGroups']) ;
                    }
                    $xjRes['cards'] = $xianjCard;
                    //echo "闲->{$xjSeatNo}<br>".print_r($xjRes,true);
                    //比大小：第一步，比KEY值；
                    if($zjNiuLevel > $xjLevel){              //牛相比； 庄赢；
                        $lastWin = 1 ;
                    }else if($zjNiuLevel < $xjLevel){        //牛相比； 闲赢；
                        $lastWin = 2 ;
                    }else if ($zjNiuLevel == $xjLevel) {     //牛相同，比其它； 点数；
                        //牛牛相同时：比较大小；闲赢还是庄赢；
                        $lastWin = self::gatherWhoWin($xjLevel,$zjRes,$xjRes);
                    }
                    
                    $xianScore = 0; //TODO 计算输赢的钱数据；
                    $zjMoney = self::countWinMoney($lastWin,$fjmoney,$zjMutle,$zjCardmutl,$xjBets,$xjCardMut,$xjMoney,$zjOldFee,$xjOldFee,$xianScore); // 以小博大(防止输多，赢多操作)
                    $xjSWin[$xjUserId] = $xianScore;
                    
                    //TODO 闲家实际输赢；
                    $xjLastMoney = $xjMoney;
                    $zjFees[] = abs($zjMoney) ;         //TODO 庄家下注额
                    
                    //TODO 闲家输赢数据（总下注 ＝ 有效下注 + 抽 水）
                    $cellScore = abs($xjMoney);
                    if (isset($xjMoney) && floatval($xjMoney) > 0) {
                        $xjWater = bcmul($xjMoney, BaseComm::getSetWaterDott() , 2);    //TODO 最后计算抽水的钱；
                        $xjLastMoney = bcsub($xjMoney, $xjWater , 2);                   //TODO 闲家实际输赢，赢分抽水处理
                    }
                    
                    $zjTotalMoney = bcadd($zjTotalMoney, $zjMoney,2);
                    $zjCellScore = bcadd($zjCellScore, abs($zjMoney),2);                     //TODO 庄家有效下注 = 所有玩家参与的money
                    $xjBetMoney = abs($xjMoney);    
                    
                    //TODO 玩家的下注的钱:玩家赢的钱，和输的钱：只有正数；
                    $moneyArr[$xjSeatNo] = array(
                        "uid"=> $xjUserId,
                        "seatNo"=>$xjSeatNo,
                        "money"=>floatval($xjMoney),
                        "allBetScore"=>abs($xjMoney),                           // 总下注分
                        "cellScore"=>floatval($cellScore),                      // 有效下注分
                        "lastPoints"=>  floatval($xjLastMoney),                 // 实际输赢（除去水钱）
                        "water"=> floatval($xjWater),
                        "level" => $xjLevel,
                        "card_mutle" => $xjCardMut,
                        "zj"=>'闲',
                        "cards"=> $xianjCard
                    );
                }
            }
            //闲家信息没有问题
            if(!empty($moneyArr) && sizeof($moneyArr) > 1 ){
                //TODO 计算玩家最后输赢的分
                $zjLastMoney =  $zjTotalMoney;
                $zjWater = 0;
                BaseEnum::Logger("计算庄家位输赢：Uid={$zjUserId},oldpoints={$zjOldFee}, 实际输赢={$zjLastMoney}，闲家理论计算=>".json_encode($xjSWin) , "user-login");
                if (isset($zjTotalMoney) && floatval($zjTotalMoney) > 0) {
                    $zjWater = bcmul($zjTotalMoney, BaseComm::getSetWaterDott() , 2);       //TODO 最后计算抽水的钱；
                    $zjLastMoney = bcsub($zjTotalMoney, $zjWater,2);                        //TODO 大于0要抽掉水线
                }
                //TODO ###玩家分数不够输的情况( 重新计算 )  ###
                else if ($zjTotalMoney < 0 && abs($zjTotalMoney) > $zjOldFee  && !empty($xjSWin)){
                    $newChange = [];
                    $newzjCellScore = 0;
                    $zjAllTempScore =  $zjOldFee;   //TODO 庄家原来的钱
                    //TODO 合计起来，再处理特殊情况 ：庄家钱不赔线的情况；
                    foreach ($xjSWin as $vuid => $vppo){
                        //TODO 先把庄家赢的收回来 (再把庄家所有分数 ===>分配给其它赢的玩家)
                        if ($vppo < 0) {
                            unset($xjSWin[$vuid]);
                            $zjAllTempScore += floatval(abs($vppo));  //累加庄家的分数
                            $newzjCellScore += floatval(abs($vppo));
                        }
                    }
                    $sumOther = !empty($xjSWin) ? array_sum($xjSWin) : 0 ;
                    BaseEnum::Logger("重新分配庄家的分数：[{$zjUserId},old={$zjOldFee}],收回[输]玩家points={$zjAllTempScore}，还要赔Money={$sumOther},详细=>".json_encode($xjSWin) , "user-login");
                    
                    //TODO 庄家不够赔就对其它玩家的赔本进行平分庄家本钱 [OMG]
                    if (!empty($xjSWin) && $sumOther>0 && $sumOther > $zjAllTempScore) {
                        $newzjCellScore += array_sum($xjSWin);
                        foreach ($xjSWin as $pvuid => $epog){
                            if ($epog > 0) {
                                $tempopg = bcmul($zjAllTempScore, abs($epog) / $sumOther , 3);              //TODO  按比列平分
                                $tempWater = floatval(bcmul($tempopg, BaseComm::getSetWaterDott() ,2));     //TODO  最后计算抽水的钱；
                                
                                //TODO 平分  (庄家 输光)
                                $newChange[$pvuid] = [
                                    "changePoint" => floatval($tempopg) - $tempWater, 
                                    "cellScore" => floatval($tempopg) ,
                                    "water" => $tempWater
                                ];
                            }
                        }
                    }
                    //TODO 重新分配对应的玩家分数据
                    if(!empty($newChange)){
                        $zjLastMoney = 0 - $zjOldFee;       //TODO (庄家 输光)
                        $zjCellScore = $newzjCellScore;     //TODO (庄家 有效下注 == 全输那部分)
                        foreach ($moneyArr as $vsid => $onelineMon){
                            $tempuidd = $onelineMon['uid'] ?? 0;
                            $tempwinscore = $onelineMon['lastPoints'] ?? 0;
                            $tempinfo = $newChange[$tempuidd] ?? FALSE;
                            //TODO 平分庄家的总资产
                            if(intval($tempuidd) >0 && !empty($tempinfo) && floatval($tempwinscore) > 0) {
                                $moneyArr[$vsid]['lastPoints'] = $tempinfo["changePoint"] ?? 0.0;   //实际赢的分数
                                $moneyArr[$vsid]['cellScore'] = $tempinfo["cellScore"] ?? 0.0;      //实际赢的分数
                                $moneyArr[$vsid]['water'] = $tempinfo["water"] ?? 0.0;              //实际抽水钱
                            }
                        }
                        BaseEnum::Logger("重新分配结束：[{$zjUserId},最后输赢={$zjLastMoney}],有效={$zjCellScore}，闲家详细=> ".json_encode($newChange) , "user-login");
                    }
                }
                
                //TODO 庄家最后的结算值
                $moneyArr[$zjSeatNo] = array(
                    "uid"=> $zjUserId,
                    "seatNo"=> $zjSeatNo,
                    "money"=>floatval($zjTotalMoney),
                    "allBetScore"=>!empty($zjFees) ? array_sum($zjFees) : 0,                // 总下注分
                    "cellScore"=> floatval($zjCellScore),                                   // 有效下注分
                    "lastPoints"=>  floatval($zjLastMoney),                                 // 实际输赢（除去水钱）
                    "eachprice"=>abs($zjTotalMoney),
                    "water"=>floatval($zjWater) ,
                    "level" => $zjNiuLevel,
                    "card_mutle" => $zjCardmutl,
                    "bet"=>'庄',
                    "cards"=> $zjcode
                );
                
                //TODO 手牌信息组合；包含信息：总共多少位置，每个玩家的手牌，庄家位置信息；
                $cardValue = BaseComm::conectUserCardsValue($gameUtype,$fjmaxPeop,$allCards,$zjSeatNo);
                $returndata["cardvalues"] = !empty($cardValue) ? $cardValue : "";               //手牌组合数据
            }
        }
        return $moneyArr;
    }
    
    /**
     * 计算下注最高倍数
     */
    public static function countDeskMaxMutle($totalNum,$zjMuts,$zjPoints,$fjInfo=false){
        $roomEveryPots = isset($fjInfo["everyPoints"]) ? floatval($fjInfo["everyPoints"]) :0 ;  //房间底分
        $minMutl = isset($fjInfo["minMultiple"]) ? intval($fjInfo["minMultiple"]) :0 ;          //房间最高倍
        $maxMutl = isset($fjInfo["maxMultiple"]) ? intval($fjInfo["maxMultiple"]) :0 ;          //房间最高倍
        BaseEnum::Logger("计算倍数参数：everyPoints={$roomEveryPots},minMutl={$minMutl},maxMutl={$maxMutl},totalNum={$totalNum},zjPoints={$zjPoints},zjMutls ={$zjMuts}===","user-login");
        if(!$totalNum || intval($totalNum) < 2 || intval($zjMuts) <= 0  ||!$zjPoints || !$fjInfo || !$roomEveryPots) return 0;
        $lastNum = $totalNum - 1;
        $lastTimes = intval($zjPoints / ($roomEveryPots * 4 * $zjMuts * $lastNum)) ;            //取理论值；
        if (isset($maxMutl) && $maxMutl > 0 && $lastTimes > $maxMutl) {
            $lastTimes = $maxMutl; //不超过最高倍；
        }
        BaseEnum::Logger("计算倍数结果：lastTimes={$lastTimes},lastNum={$lastNum} ===","user-login");
        return $lastTimes > 0 ? $lastTimes : 0;
    }
    
    
    
    /**
     * TODO 计算庄输赢数据（不考虑赢家抽水的情况）
     * @param bool 庄家赢为True
     * @param number $xianMoney 闲家输赢分( 参与以小博大之后的值)
     * @param number $xianScore 闲家输赢分( 理论计算的值)
     */
    public static function countWinMoney($mainwin = 1,$fjmoney = 0,$zjMutle=0,$zjCardmutl = 1,$xjBets=1,$xjCardMut = 1,& $xianMoney = 0,$zjFee=0,$xjFee = 0,&$xianScore = 0) {
        //TODO 庄赢 ：庄家胜利所赢 ＝ A*M*X*Y －抽水 | 闲家失败所输 ＝ A*M*X*Y
        $mainMoney = 0;
        if (intval($mainwin) === 1) {
            $tempMon = $fjmoney * $zjCardmutl * $zjMutle * $xjBets ;                    //A*M*X*Y
            $mainMoney = bcsub($tempMon, 0,2);              //庄家赢的
            $xianMoney = bcsub(0, $tempMon,2) ;                                         //闲家输的
        }else{
            //庄输；庄家失败所输 ＝ A*N*X*Y | 闲家胜利所赢 ＝ A*N*X*Y －抽水
            $tempMon = $fjmoney * $xjCardMut * $zjMutle * $xjBets ;                     //A*N*X*Y
            $mainMoney = bcsub(0, $tempMon,2) ;                                         //闲家赢的
            $xianMoney = bcsub($tempMon, 0,2);              //庄家输的
        }
        $xianScore = $xianMoney;    //TODO 理论计算闲家的输赢值
        
        $ifMadd = ($mainMoney>0) ? 1 : -1;
        //TODO 防以小博大  [庄赢=闲输]（ 输值： 不超过自身最大携带金额） 
        if($zjFee > 0 && abs($mainMoney) > $zjFee){
            $mainMoney = $ifMadd * $zjFee ;            //TODO (取赢方：携带最高值-> 赢自己携带分回来)
            $xianMoney = -1 * $mainMoney;              //TODO 闲家相反的操作
        }
        if($xjFee>0 && abs($mainMoney) > $xjFee ){
            $mainMoney = $ifMadd * $xjFee;
            $xianMoney = -1 * $mainMoney;            //TODO (取输方：携带最高值-> 全输光)
        }
        return $mainMoney ;
    }
     
}